//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   testInputXML.cc
 * \author Jeremy Roberts
 * \date   11/05/2010
 * \brief  test of class LegendrePoly
 * \note   Copyright (C) 2010 Jeremy Roberts
 */
//---------------------------------------------------------------------------//
// $Rev:: 56                                            $:Rev of last commit
// $Author:: bert                                       $:Author of last commit
// $Date:: 2010-11-08 20:29:53 -0500 (Mon, 08 Nov 2010) $:Date of last commit
//---------------------------------------------------------------------------//
#include <iostream>
//#include <cstdlib>
//#include <cstring>
#include <string>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/relaxng.h>

using namespace std;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// xml file structure
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct xmlFileInfo 
{
    /// filename currently being processed
    string filename;  
    /// pointer to the schema URI used for this file
    string* schema;   
    /// XML doc ptr for input file
    xmlDocPtr doc;    
    /// XML XPath search context
    xmlXPathContextPtr xpathCtxt; 
} *curFilePtr; 


struct Input
{
  string name;
  int    rfsink;
  double epss;
  double epsk;
};


/// primary schema used for Cyclus processing
static string main_schema = "serment.rng";

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// gets an element from xml input?
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlNodePtr get_xpath_element(xmlNodePtr cur,const char* expression)
{
	xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  	xpathCtxt->node = cur;
  	/* Evaluate xpath expression */
  	xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  	if(xpathObj == NULL) 
	{
    	fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    	xmlXPathFreeContext(xpathCtxt); 
  	}
  	return xpathObj->nodesetval->nodeTab[0];
}
xmlNodePtr get_xpath_element(const char* expression)
  {
    return get_xpath_element(curFilePtr->doc->children,expression);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// extract actual content?  Need a way to extract different types
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* get_xpath_content(xmlNodePtr cur,const char* expression)
{
  	xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  	xpathCtxt->node = cur;
  	/* Evaluate xpath expression */
  	xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
	fprintf(stderr,"---> xpath expression \"%s\"\n", expression);
  	if(xpathObj == NULL) 
	{
    	fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    	xmlXPathFreeContext(xpathCtxt); 
  	}
    if(xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
    {
		cout << " empy set " << endl;
    	return "";
    }
	else
	{
		cout << xmlXPathNodeSetGetLength(xpathObj->nodesetval) << endl;
	}
    fprintf(stderr,"here: \"%s\"\n", (const char*)(xpathObj->nodesetval->nodeTab[0]->children->content));
  	return (const char*)(xpathObj->nodesetval->nodeTab[0]->children->content);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// validate
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlDocPtr validate_file(xmlFileInfo *fileInfo)
{
	xmlRelaxNGParserCtxtPtr ctxt = xmlRelaxNGNewParserCtxt(fileInfo->schema->c_str());
  	if (NULL == ctxt)
  	{
		cout << "Failed to generate parser from schema!" << endl;
  	}
	xmlRelaxNGPtr schema = xmlRelaxNGParse(ctxt);
	xmlRelaxNGValidCtxtPtr vctxt = xmlRelaxNGNewValidCtxt(schema);
    xmlDocPtr doc;
	doc = xmlReadFile(fileInfo->filename.c_str(), NULL,0);
	if (NULL == doc) 
	{
		cout << "Failed to parse " << fileInfo->filename << endl;
  	}
  	if (xmlRelaxNGValidateDoc(vctxt,doc))
	{
		cout << " File " << fileInfo->filename << " is NOT valid against schema " 
             << *(fileInfo->schema) << endl;
	}
  	else
	{
    	cout << "File " << fileInfo->filename << " is valid against schema " 
    	     << *(fileInfo->schema) << endl;
	}
  	return doc;	
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// load the xml input
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void load_file(string filename)
{
	curFilePtr = new xmlFileInfo;
	xmlFileInfo &inputFile = *curFilePtr;
	inputFile.filename = filename;
  	inputFile.schema = &main_schema;
  	inputFile.doc = validate_file(&inputFile);
  	/* Create xpath evaluation context */
  	inputFile.xpathCtxt = xmlXPathNewContext(inputFile.doc);
  	if(inputFile.xpathCtxt == NULL) 
	{
    	fprintf(stderr,"Error: unable to create new xpath context \n");
  	}
  	// Do something with the actual file now
	
	Input inp;

	// get name
    xmlNodePtr cur = get_xpath_element("/globalinput");
    inp.name = (get_xpath_content(cur,"name"));
	cout << " inp.name = " << inp.name << endl;
	// move on to control
    cur = get_xpath_element("/*/globalcontrol");
    inp.rfsink = atoi((get_xpath_content(cur,"rfsink")));
    inp.epss   = atof(get_xpath_content(cur,"epss"));
    
	string tmp;

	cout << " inp.rfsink = " << inp.rfsink << endl;
	cout << " inp.epss = " << inp.epss << endl;

	tmp = get_xpath_content(cur,"epsk");
	inp.epsk = 0.1;
    if (tmp != "")
	{
		inp.epsk = atof(get_xpath_content(cur,"epsk"));
	}

    // try counting the z planes
    cur = get_xpath_element("/*/globalgeometry");
    get_xpath_content(cur,"zplane");

	//xmlXPathNodeSetGetLength
	
}


//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// test program for reading xml
// It should be easy to get the input working with the current class structure.
// And since the getlength thing works, it will be easy to check for self-
// consistency w/r to elemz and the actual number of zplanes, etc.
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(int argc, char* argv[])
{
    // announce yourself
    cout << " test xml..... " << endl;
    // read input file
    load_file(argv[1]);
    

    return 0;
}
